
/*
一个游戏服务器,一个游戏的方式
服务启动后,调用 initAndStartGame 初始化游戏

*/
import { GameMsgCall } from "../api/base";
import { Game } from "../Game";
import { ClientConnection, gameServer, gameConnMgr } from "../server";
import { MsgInpFrame } from "../shared/gameClient/protocols/MsgInpFrame";
import { IArea, ICountry, IMap, InputType, IPlayer } from "../shared/gameClient/games/OccupationTheWarModels";
import { v4 } from "uuid";
import { hasProperty } from "../shared/tsgf/Utils";

/**占领战争游戏, 全局初始化一个即可*/
export class OccupationTheWarGame {
    public game: Game;
    /**地图数据,只有第一帧时完整有效,其他时候只用来确认是否有可用国家*/
    map!: IMap;

    constructor(syncFrameRate = 60) {
        this.game = new Game(syncFrameRate);

        gameConnMgr.onConnAuthed((conn, reconnectOldConnId) => {
            if (!this.game.inGaming) {
                //如果当前游戏没在进行,则启动游戏
                this.initGame();
            }
            //发送追帧数据
            this.game.connectionAfterFrames(conn);
            //插入一个新增玩家的输入(也可能是断线重连,将改玩家之前的国家转到新的连接下)
            this.game.addConnectionInpFrame(conn.connectionId, {
                operates: [
                    {
                        inputType: InputType.NewPlayer,
                        userName: conn.userInfo.userName,
                        reconnectOldConnId: reconnectOldConnId,
                    }
                ]
            });
        });
        gameConnMgr.onConnDiconnect((connId, userInfo) => {
            //支持断线重连
            return true;
        });
        gameConnMgr.onUserDisconnect((connId, userInfo) => {
            if (!gameConnMgr.hasUser()) {
                //如果没有用户了,则停止游戏,直接清理数据
                this.clearGame();
            } else {
                //插入一个移出玩家的输入帧
                this.game.addConnectionInpFrame(connId, {
                    operates: [
                        { inputType: InputType.RemovePlayer }
                    ]
                });
            }
        });
    }

    initGame() {
        this.game.startGame();
        //将服务器初始化的地图数据,作为最早的同步数据
        this.map = this.initMap();
        this.game.syncStateData(this.map, -1);
    }
    clearGame() {
        this.game.stopGame();
    }


    /**
     * 生成随机连续的区域
     * @date 2022/3/17 - 下午6:20:47
     *
     * @param {number} count
     * @param {number} mapX
     * @param {number} mapZ
     * @param {{ [x_z: string]: boolean }} existsCheck
     * @returns {(number[][] | null)}
     */
    createRndLinkArea(allArea: IArea[], count: number, mapX: number, mapZ: number, existsCheck: { [x_z: string]: boolean }, rndSp: number, areaSize: number): IArea[] | null {
        let xz = this.rndLinkArea(count, mapX, mapZ, existsCheck);
        if (!xz) return null;
        var areaList: IArea[] = [];
        for (let i = 0; i < xz.length; i++) {
            let x = xz[i][0] * rndSp + areaSize / 2;
            let z = xz[i][1] * rndSp + areaSize / 2;
            var area: IArea = {
                areaIndex: allArea.length,
                countryId: null,
                troopsMax: 50,
                troopsCurr: 50,
                troopsCurrCalculate: 50,
                troopsInc: 3,
                troopsPreFSIndex: 0,
                x: x,
                z: z,
            };
            allArea.push(area);
            areaList.push(area);
        }
        return areaList;
    }
    /**
     * 随机获取一个连续的区域
     * @date 2022/3/17 - 下午6:20:47
     *
     * @param {number} count
     * @param {number} mapX
     * @param {number} mapZ
     * @param {{ [x_z: string]: boolean }} existsCheck
     * @returns {(number[][] | null)}
     */
    rndLinkArea(count: number, mapX: number, mapZ: number, existsCheck: { [x_z: string]: boolean })
        : number[][] | null {
        let xz: number[][] | null;
        let x = 0, z = 0;
        do {
            x = Math.floor(Math.random() * mapX);
            z = Math.floor(Math.random() * mapZ);
        } while ((xz = this.getLinkArea(count, x, z, mapX, mapZ, existsCheck)), !xz);
        for (let i = 0; i < xz.length; i++) {
            existsCheck[xz[i][0] + '_' + xz[i][1]] = true;
        }
        return xz;
    }

    /**
     * 获取坐标是否存在上下左右足够的空间,返回指定数量的空位数组
     * @date 2022/3/17 - 下午6:15:32
     *
     * @param {number} count
     * @param {number} x
     * @param {number} z
     * @param {{ [x_z: string]: boolean }} existsCheck
     * @returns {(number[][] | null)}
     */
    getLinkArea(count: number, x: number, z: number, mapX: number, mapZ: number, existsCheck: { [x_z: string]: boolean })
        : number[][] | null {
        if (existsCheck[x + '_' + z]) return null;
        let xz: number[][] = [[x, z]];
        //先算出第一个
        if (count > xz.length && xz[0][1] > 0) {
            //不够,z-1
            let x = xz[0][0], z = xz[0][1] - 1;
            if (!existsCheck[x + '_' + z]) xz.push([x, z]);
        }
        if (count > xz.length && xz[0][1] < mapZ - 1) {
            //不够,z+1
            let x = xz[0][0], z = xz[0][1] + 1;
            if (!existsCheck[x + '_' + z]) xz.push([x, z]);
        }
        if (count > xz.length && xz[0][0] > 0) {
            //不够,x-1
            let x = xz[0][0] - 1, z = xz[0][1];
            if (!existsCheck[x + '_' + z]) xz.push([x, z]);
        }
        if (count > xz.length && xz[0][0] < mapX - 1) {
            //不够,x+1
            let x = xz[0][0] + 1, z = xz[0][1];
            if (!existsCheck[x + '_' + z]) xz.push([x, z]);
        }
        if (count > xz.length) {
            //最终还是不够, 返回null
            return null;
        }
        return xz;
    }


    initMap(): IMap {
        let map: IMap = {
            allPlayer: {},
            allCountry: {},
            allAttackingTroop: {},
            allArea: [],
        };
        const mapSizeX = 20;//地图总大小
        const mapSizeZ = 40;//地图总大小
        const areaSize = 1;//地域建筑占地尺寸(x,正方形)
        const areaCount = 40;//总共地域数量
        const areaInterval = 2;//地域之间的间隔
        const countryCount = 20;//总共多少个国家
        const countryAreaCount = 2;//每个国家初始多少个地域,不能超过5个

        //初始化区域, 同个国家的随机区域放一起
        var existsCheck: { [x_z: string]: boolean } = {};
        var rndSp = areaSize + areaInterval;
        var mapX = mapSizeX / rndSp;
        var mapZ = mapSizeZ / rndSp;
        for (let i = 0; i < countryCount; i++) {
            var areaList = this.createRndLinkArea(map.allArea, countryAreaCount, mapX, mapZ, existsCheck, rndSp, areaSize);
            if (!areaList) {
                continue;
            }
            var country: ICountry = {
                countryId: v4(),
                playerConnId: null,
                name: "中立" + (i + 1),
            };
            for (let j = 0; j < areaList.length; j++) {
                var a = areaList[j];
                a.countryId = country.countryId;
            }
            map.allCountry[country.countryId] = country;
        }
        //补充剩下的无主之地
        for (let i = countryCount * countryAreaCount; i < areaCount; i++) {
            this.createRndLinkArea(map.allArea, 1, mapX, mapZ, existsCheck, rndSp, areaSize);
        }


        return map;
    }

}

/**当前游戏服务器范围的游戏实例,需要服务启动后调用 initAndStartGame(...) */
let globalGame: OccupationTheWarGame;

/**
 * 初始化和启动全局游戏
 * @param [syncFrameRate] 
 */
function initAndStartGlobalGame(syncFrameRate = 60) {
    globalGame = new OccupationTheWarGame(syncFrameRate);
}

export {
    initAndStartGlobalGame,
    globalGame,
};
